package api

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/gin-gonic/gin"
	"go-chain-api/contract"
	"go-chain-api/contract/evmAbi"
	"go-chain-api/global"
	models "go-chain-api/internal/model"
	"go-chain-api/tools"
	"go-chain-api/utils"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"math"
	"math/big"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

type Block struct {
}

type BlockInfo struct {
	BlockHeight       uint64 `json:"block_height"`
	BlockHash         string `json:"block_hash"`
	ParentHash        string `json:"parent_hash"`
	LatestBlockHeight uint64 `json:"latest_block_height"`
	Timestamp         uint64 `json:"timestamp"`
	BlockReward       string `json:"block_reward"`
	Difficulty        string `json:"difficulty"`
	Size              uint64 `json:"size"`
	GasUsed           uint64 `json:"gas_used"`
	GasLimit          uint64 `json:"gas_limit"`
	TransactionsCount int    `json:"transactions_count"`
	ExtraData         []byte `json:"extra_data"`
}

func (v1 Block) GetLastBlocks(c *gin.Context) {
	var response global.Response

	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	blocks := models.GetLatest20(chainName, chainId)
	response = global.Response{
		Code: http.StatusOK,
		Data: blocks,
		Msg:  "success",
	}
	c.JSON(http.StatusOK, response)
}

// GetTokensRecords 获取代币转账记录
func (v1 Block) GetTokensRecords(c *gin.Context) {
	var response global.Response
	address := c.DefaultQuery("address", "")
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	address = common.HexToHash(address).String()

	// 查询总条数
	count := models.GetDataByAddressCount(chainName, chainId, address)
	if int(count) == 0 {
		response = global.Response{
			Code: http.StatusOK,
			Data: global.Page{
				Total: 0,
				List:  []string{},
			},
			Msg: "success",
		}
		c.JSON(http.StatusOK, response)
		return
	}

	lists := models.GetTokenRecordByAddress(chainName, chainId, address, pageIndex, pageSize)
	response = global.Response{
		Code: http.StatusOK,
		Data: global.Page{
			Total: count,
			List:  lists,
		},
		Msg: "success",
	}
	c.JSON(http.StatusOK, response)
}

// GetBlockByPage 获取区块列表
func (v1 Block) GetBlockByPage(c *gin.Context) {
	var response global.Response
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	blocks, _ := models.GetBlockInfoByName(chainName, chainId)

	client, err := ethclient.Dial(blocks.RpcUrl)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()
	// 获取最新区块
	endBlockNumber, _ := client.BlockNumber(c)
	//if pageIndex == 0 {
	//        pageIndex = 1
	//}
	// 根据分页推算需要获取的区块
	endBlockNumber = endBlockNumber - uint64(pageIndex)*uint64(pageSize)
	startBlockNumber := endBlockNumber - uint64(pageSize)

	var blockInfos []BlockInfo
	// 获取区块
	for i := endBlockNumber; i >= startBlockNumber; i-- {
		block, err := client.BlockByNumber(c, big.NewInt(int64(i)))
		if err != nil {
			log.Fatal(err)
		}
		blockInfos = append(blockInfos, BlockInfo{
			BlockHeight:       block.NumberU64(),
			BlockHash:         block.Hash().String(),
			ParentHash:        block.ParentHash().String(),
			LatestBlockHeight: endBlockNumber,
			Timestamp:         block.Time(),
			BlockReward:       block.BaseFee().String(),
			Difficulty:        block.Difficulty().String(),
			Size:              block.Size(),
			GasUsed:           block.GasUsed(),
			GasLimit:          block.GasLimit(),
			TransactionsCount: len(block.Transactions()),
		})
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: global.Page{
			Total: int64(endBlockNumber),
			List:  blockInfos,
		},
		Msg: "success",
	}

	c.JSON(http.StatusOK, response)
}

func (v1 Block) GetBlockByNumber(c *gin.Context) {
	var response global.Response
	blockNumber := c.DefaultQuery("blockNumber", "1")
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	blocks, _ := models.GetBlockInfoByName(chainName, chainId)

	client, err := ethclient.Dial(blocks.RpcUrl)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	blockNumberInt, _ := new(big.Int).SetString(blockNumber, 10)
	block, err := client.BlockByNumber(c, blockNumberInt)
	if err != nil {
		log.Fatal(err)
	}
	response = global.Response{
		Code: http.StatusOK,
		Data: BlockInfo{
			BlockHeight:       block.NumberU64(),
			BlockHash:         block.Hash().String(),
			ParentHash:        block.ParentHash().String(),
			LatestBlockHeight: blockNumberInt.Uint64(),
			Timestamp:         block.Time(),
			BlockReward:       block.BaseFee().String(),
			Difficulty:        block.Difficulty().String(),
			Size:              block.Size(),
			GasUsed:           block.GasUsed(),
			GasLimit:          block.GasLimit(),
			TransactionsCount: len(block.Transactions()),
		},
		Msg: "success",
	}

	c.JSON(http.StatusOK, response)
}

func (v1 Block) GetTxRecords(c *gin.Context) {
	var response global.Response
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.MustGet("chainName").(string)

	count, last20, err := models.GetTransactionRecords(chainName, pageIndex, pageSize)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "get tx fail",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	// 查询总条数
	response = global.Response{
		Code: http.StatusOK,
		Data: global.Page{
			Total: count,
			List:  last20,
		},
		Msg: "success",
	}
	c.JSON(http.StatusOK, response)
}

func (v1 Block) GetTxByHash(c *gin.Context) {
	var response global.Response
	txHash := c.Query("txHash")

	// 参数校验
	if txHash == "" {
		response = global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "txHash is required",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	hash, err := models.GetTransactionByHash(c.MustGet("chainName").(string), txHash)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "get tx fail",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: hash,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)
}

func (v1 Block) GetTxByAddress(c *gin.Context) {
	var response global.Response
	address := c.DefaultQuery("address", "")
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)

	byAddress, list, err := models.GetTransactionByAddress(chainName, chainId, address, pageIndex, pageSize)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "get tx fail",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: global.Page{
			Total: byAddress,
			List:  list,
		},
		Msg: "success",
	}

	c.JSON(http.StatusOK, response)
}

// GetTokenHolders 获取token持有者
func (v1 Block) GetTokenHolders(c *gin.Context) {
	var response global.Response
	token := c.DefaultQuery("token", "")
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	count, err := models.GetTokenHoldersCount(chainName, chainId, token)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	response = global.Response{
		Code: http.StatusOK,
		Data: count,
		Msg:  "success",
	}
	c.JSON(http.StatusOK, response)
}

// GetTokenTransferCount 获取token转账总数
func (v1 Block) GetTokenTransferCount(c *gin.Context) {
	var response global.Response
	token := c.DefaultQuery("token", "")
	chainName := c.MustGet("chainName").(string)

	count, err := models.GetTokenTxCount(chainName, token)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: count,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)
}

// GetTokenTransferAmount 获取token转账总额
func (v1 Block) GetTokenTransferAmount(c *gin.Context) {
	var response global.Response
	token := c.DefaultQuery("token", "")
	chainName := c.MustGet("chainName").(string)

	amount, err := models.GetTokenTransferAmount(chainName, token)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: amount,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)
}

// GetMinerFee 获取最少的矿工费
func (v1 Block) GetMinerFee(c *gin.Context) {
	var response global.Response
	chainName := c.MustGet("chainName").(string)
	fee, err := models.GetMinerFee(chainName)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "get miner fee fail",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	response = global.Response{
		Code: http.StatusOK,
		Data: fee,
		Msg:  "success",
	}
	c.JSON(http.StatusOK, response)
}

// GetFeeTotal 获取手续费总额
func (v1 Block) GetFeeTotal(c *gin.Context) {
	var response global.Response
	chainName := c.MustGet("chainName").(string)
	fee, err := models.GetFeeTotal(chainName)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "get miner fee fail",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	response = global.Response{
		Code: http.StatusOK,
		Data: fee,
		Msg:  "success",
	}
	c.JSON(http.StatusOK, response)
}

// GetTokenList 获取代币列表
func (v1 Block) GetTokenList(c *gin.Context) {
	var response global.Response
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	token := &models.TokenInfo{}
	tokens, err := token.GetTokenList(chainName, chainId)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "get tokens fail",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: tokens,
		Msg:  "success",
	}
	c.JSON(http.StatusOK, response)
}

// GetBalance 获取余额
func (v1 Block) GetBalance(c *gin.Context) {
	var response global.Response
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	address := c.Query("address")
	if address == "" {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "address is empty",
		}
		c.JSON(http.StatusInternalServerError, response)
		return

	}

	//address = common.HexToAddress(address).Hex()
	// 获取rpc地址
	blockInfo, err := models.GetBlockInfoByName(chainName, chainId)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	// 获取代币列表
	token := &models.TokenInfo{}
	tokens, err := token.GetTokenList(chainName, chainId)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	// 创建结构体
	type BalanceInfo struct {
		Name    string `json:"name"`
		Balance string `json:"balance"`
		Token   string `json:"token"`
	}

	var balanceList []BalanceInfo

	// 通过rpc地址获取公链币余额
	client, err := ethclient.Dial(blockInfo.RpcUrl)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	defer client.Close()

	// 查询账户余额
	balance, err := client.BalanceAt(c, common.HexToAddress(address), nil)
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	// 将余额从wei转换为以太币
	ethBalance := new(big.Float).Quo(new(big.Float).SetInt(balance), big.NewFloat(1e18))
	ethBalanceStr := ethBalance.Text('f', 9)
	balanceList = append(balanceList, BalanceInfo{
		Name:    blockInfo.ChainName,
		Balance: ethBalanceStr,
		Token:   "",
	})

	for _, token := range tokens {

		// 代币合约ABI
		parsedABI, err := abi.JSON(strings.NewReader(utils.ERC20_ABI))
		if err != nil {
			log.Println("parsedABI_err:", err)
			break
		}

		contractAddress := common.HexToAddress(token.Address)
		data, err := parsedABI.Pack("balanceOf", common.HexToAddress(address))
		if err != nil {
			log.Println("contractAddress_err:", err)
			break
		}
		// 调用balanceOf方法
		callResult, err := client.CallContract(c, ethereum.CallMsg{
			To:   &contractAddress,
			Data: data,
			From: common.HexToAddress(address),
		}, nil)
		if err != nil {
			log.Println("callResult_err:", err)
			break
		}

		// 解析结果
		balance, err := parsedABI.Unpack("balanceOf", callResult)
		if err != nil {
			log.Println("balance_err", err)
			break
		}

		tokenBalance := new(big.Float).Quo(new(big.Float).SetInt(balance[0].(*big.Int)), big.NewFloat(math.Pow10(int(token.Decimals))))
		balanceStr := tokenBalance.Text('f', int(token.Decimals)) // 将结果格式化为固定点数表示，小数点后保留的位数与代币的小数位数相同
		balanceList = append(balanceList, BalanceInfo{
			Name:    token.Symbol,
			Balance: balanceStr,
			Token:   token.Address,
		})
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: balanceList,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)
}

// 判断地址是否是合约地址
func (v1 Block) IsContractAddress(c *gin.Context) {
	response := global.Response{
		Code: http.StatusOK,
		Data: true,
		Msg:  "success",
	}
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	address := c.Query("address")
	blocks, _ := models.GetBlockInfoByName(chainName, chainId)
	boolean, err := models.IsContractAddress(blocks.RpcUrl, address)
	if err != nil {
		response.Msg = err.Error()
		response.Code = http.StatusBadRequest
	}
	response.Data = boolean
	c.JSON(http.StatusOK, response)
}

type createRequest struct {
	ChainConfigId0 string `bson:"chainConfigId0" json:"chainConfigId0"`
	ChainConfigId1 string `bson:"chainConfigId1" json:"chainConfigId1"`
	TokenId0       string `bson:"tokenId0" json:"tokenId0"`
	TokenId1       string `bson:"tokenId1" json:"tokenId1"`
	TxHash         string `bson:"txHash" json:"txHash"`
	From           string `bson:"from" json:"from"`
	To             string `bson:"to" json:"to"`
	UserId         string `bson:"userId" json:"userId"`
	Amount0        string `bson:"amount0" json:"amount0"`
	Amount1        string `bson:"amount1" json:"amount1"`
}
type listRequest struct {
	PageIndex uint   `form:"pageIndex"` // 第几页
	PageSize  uint   `form:"pageSize"`  // 每页显示条数
	UserId    string `form:"userId"`
	From      string `form:"from"`
}

type listResponse struct {
	Code int    `json:"code"`
	Data Page   `json:"data"`
	Msg  string `json:"msg"`
}

type Page struct {
	Total int64       `json:"total"`
	List  interface{} `json:"list"`
}
type RequestParam struct {
	ChainConfigId string `form:"chainConfigId"` // 第几页
}
type QueryData struct {
	UserId         string `form:"userId"`
	ChainConfigId0 string `form:"chainConfigId0"`
	ChainConfigId1 string `form:"chainConfigId1"`
	Token0         string `form:"token0"`
	Token1         string `form:"token1"`
}

func (v1 Block) Create(c *gin.Context) {
	var response global.Response
	req := new(createRequest)
	//res := new(createResponse)
	language := c.MustGet("language").(string)

	if err := c.ShouldBindJSON(req); err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.ParamBindError,
		//	Msg:  string(utils.ParamBindError),
		//}
		response := utils.GetResponse(err, utils.ExchangeError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}

	var createData models.ChainApply
	createData.UserId = req.UserId
	createData.To = req.To
	createData.From = req.From
	createData.TxHash = req.TxHash
	createData.TokenId1 = req.TokenId1
	createData.TokenId0 = req.TokenId0
	createData.ChainConfigId1 = req.ChainConfigId1
	createData.ChainConfigId0 = req.ChainConfigId0
	createData.Amount0 = req.Amount0
	createData.Amount1 = req.Amount1

	err := createData.Create(createData)
	if err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.ExchangeError,
		//	Msg:  string(utils.ExchangeError),
		//}
		response := utils.GetResponse(err, utils.ExchangeError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}
	response.Code = http.StatusOK
	response.Data = nil
	response.Msg = http.StatusText(http.StatusOK)
	c.JSON(http.StatusOK, response)
}

func (v1 Block) List(c *gin.Context) {
	//var response global.Response
	req := new(listRequest)
	res := new(listResponse)
	language := c.MustGet("language").(string)
	if err := c.ShouldBindQuery(req); err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.ParamBindError,
		//	Msg:  string(utils.ParamBindError),
		//}
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}
	var createData models.ChainApply
	total, productList, err := createData.List(req.UserId, req.From, req.PageIndex, req.PageSize)
	if err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.GetProductListError,
		//	Msg:  string(utils.GetProductListError),
		//}
		response := utils.GetResponse(err, utils.GetProductListError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}

	res.Code = http.StatusOK
	res.Data = Page{Total: total, List: productList}
	res.Msg = http.StatusText(http.StatusOK)
	//ctx.Payload(res)
	c.JSON(http.StatusOK, res)

}

func (v1 Block) TokenList(c *gin.Context) {

	var response global.Response
	req := new(RequestParam)
	//res := new(createResponse)
	language := c.MustGet("language").(string)

	if err := c.ShouldBindQuery(&req); err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.ParamBindError,
		//	Msg:  http.StatusText(http.StatusOK),
		//}
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}

	//data := new(chain_token.RequestData)
	data := req.ChainConfigId
	var tokenData models.ChainToken

	productList, err := tokenData.List(data)
	if err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.GetProductListError,
		//	Msg:  string(utils.GetProductListError),
		//}
		response := utils.GetResponse(err, utils.GetProductListError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}
	response.Code = http.StatusOK
	response.Data = productList
	response.Msg = http.StatusText(http.StatusOK)
	//ctx.Payload(res)
	c.JSON(http.StatusOK, response)

}

func (v1 Block) ApiList(c *gin.Context) {

	req := new(QueryData)
	var response global.Response
	language := c.MustGet("language").(string)

	//res := new(createResponse)
	if err := c.ShouldBindQuery(&req); err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.ParamBindError,
		//	Msg:  string(utils.ParamBindError),
		//}
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}
	var configData models.ChainConfig
	productList, err := configData.ApiList(req.UserId)
	if err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.GetProductListError,
		//	Msg:  string(utils.GetProductListError),
		//}
		response := utils.GetResponse(err, utils.GetProductListError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}

	response.Code = http.StatusOK
	response.Data = productList
	response.Msg = http.StatusText(http.StatusOK)
	//ctx.Payload(res)
	c.JSON(http.StatusOK, response)

}

func (v1 Block) GetRate(c *gin.Context) {

	req := new(QueryData)
	//res := new(createResponse)
	var response global.Response
	language := c.MustGet("language").(string)

	if err := c.ShouldBindQuery(&req); err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.ParamBindError,
		//	Msg:  string(utils.ParamBindError),
		//}
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	data := new(models.CreateChainData)
	data.Token1 = req.Token1
	data.Token0 = req.Token0
	data.ChainConfigId0 = req.ChainConfigId0
	data.ChainConfigId1 = req.ChainConfigId1
	data.UserId = req.UserId

	var ChainData models.ChainToChain
	productList, err := ChainData.GetRate(data)
	if err != nil {
		//response = global.Response{
		//	Code: http.StatusOK,
		//	Data: utils.GetProductListError,
		//	Msg:  string(utils.GetProductListError),
		//}
		//utils.GetResponse(err, http.StatusOK, response, "")
		response := utils.GetResponse(err, utils.GetProductListError, nil, language)

		c.JSON(http.StatusOK, response)
		return
	}
	response.Code = http.StatusOK
	response.Data = productList.Rate.String()
	response.Msg = http.StatusText(http.StatusOK)
	//ctx.Payload(res)
	c.JSON(http.StatusOK, response)
}

func (v1 Block) GetTokenInfo(c *gin.Context) {
	var response global.Response
	address := c.Query("address")
	var token models.TokenInfo
	tokenInfo := token.GetTokenInfoByAddress(address)

	if tokenInfo != nil {
		response.Code = http.StatusOK
		response.Data = tokenInfo
		response.Msg = http.StatusText(http.StatusOK)
		//ctx.Payload(res)
		c.JSON(http.StatusOK, response)
		return
	}

	// 不存在数据库中 获取代币详情
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	blocks, _ := models.GetBlockInfoByName(chainName, chainId)
	client, err := ethclient.Dial(blocks.RpcUrl)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()
	name, err := utils.CallContractMethod(client, common.HexToAddress(address), utils.ERC20_ABI, "name")
	if err != nil {
		log.Printf("failed to get token: %v", err)
	}
	symbol, err := utils.CallContractMethod(client, common.HexToAddress(address), utils.ERC20_ABI, "symbol")
	if err != nil {
		log.Printf("failed to get token: %v", err)
	}
	decimals, err := utils.CallContractMethod(client, common.HexToAddress(address), utils.ERC20_ABI, "decimals")
	if err != nil {
		log.Printf("failed to get token: %v", err)
	}

	totalSupply, err := utils.CallContractMethod(client, common.HexToAddress(address), utils.ERC20_ABI, "totalSupply")
	if err != nil {
		log.Printf("failed to get token: %v", err)
	}

	token.ChainID = int64(chainId)
	token.ChainName = chainName
	token.Address = common.HexToAddress(address).Hex()
	token.Name = name[0].(string)
	token.Symbol = symbol[0].(string)
	token.Decimals = uint(decimals[0].(uint8))
	token.TotalSupply = totalSupply[0].(*big.Int).String()

	response.Code = http.StatusOK
	response.Data = token
	response.Msg = http.StatusText(http.StatusOK)
	c.JSON(http.StatusOK, response)
}

type TxData struct {
	From         string `json:"from"`
	To           string `json:"to"`
	TxHash       string `json:"hash"`
	Value        string `json:"value"`
	TokenValue   string `json:"tokenValue"`
	TokenName    string `json:"tokenName"`
	GasFee       string `json:"gasFee"`
	Timestamp    uint64 `json:"timestamp"`
	Status       uint64 `json:"status"`
	TokenAddress string `json:"tokenAddress"`
}

func (v1 Block) GetRecordByAddress(c *gin.Context) {
	var response global.Response
	address := c.DefaultQuery("address", "")
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	tokenAddress := c.Query("tokenAddress")
	flag := c.DefaultQuery("flag", "0")

	if address == "" {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "address is empty",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	// 查询链信息
	configData, err := models.GetConfigData(chainName, chainId, "")
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	// 查询代币详情
	token := &models.TokenInfo{}
	tokenInfo := &models.TokenInfo{}

	// 主币交易
	if len(tokenAddress) < 10 {
		// 查询交易记录
		dataList, err := models.GetMainRecordByAddress(configData.ChainName, uint(configData.ChainID), address, pageIndex, pageSize, flag)
		if err != nil {
			c.JSON(http.StatusInternalServerError, global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			})
			return
		}

		c.JSON(http.StatusOK, global.Response{
			Code: http.StatusOK,
			Data: dataList,
			Msg:  "",
		})
		return
	} else {
		tokenInfo = token.GetTokenInfoByAddress(tokenAddress)
	}
	if tokenInfo == nil {
		// 数据库中没有查询到 调用合约查询
		client, err := ethclient.Dial(configData.RpcUrl)
		if err != nil {
			log.Println(err)
		}
		tokenName, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "name")
		if err != nil {
			c.JSON(http.StatusInternalServerError, global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			})
			return
		}
		tokenSym, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "symbol")
		if err != nil {
			c.JSON(http.StatusInternalServerError, global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			})
		}
		tokenDec, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "decimals")
		if err != nil {
			c.JSON(http.StatusInternalServerError, global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			})
			return
		}
		tokenTot, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "totalSupply")
		if err != nil {
			c.JSON(http.StatusInternalServerError, global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			})
			return
		}

		tokenInfo = &models.TokenInfo{}
		// 插入到token表中
		tokenInfo.Name = tokenName[0].(string)
		tokenInfo.Symbol = tokenSym[0].(string)
		tokenInfo.Decimals = uint(tokenDec[0].(uint8))
		tokenInfo.Address = common.HexToAddress(tokenAddress).Hex()
		tokenInfo.ChainName = configData.ChainName
		tokenInfo.ChainID = configData.ChainID
		tokenInfo.TotalSupply = tokenTot[0].(*big.Int).String()
		err = tokenInfo.AddToken()
		if err != nil {
			c.JSON(http.StatusInternalServerError, global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			})
			return
		}
	}

	// 查询交易记录
	dataList, err := models.GetRecordByAddressAndContract(configData.ChainName, uint(configData.ChainID), address, tokenAddress, pageIndex, pageSize, tokenInfo.Decimals, flag)
	if err != nil {
		c.JSON(http.StatusInternalServerError, global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, global.Response{
		Code: http.StatusOK,
		Data: dataList,
		Msg:  "",
	})

}

//func (v1 Block) GetTransferRecord(c *gin.Context) {
//	var response global.Response
//	address := c.DefaultQuery("address", "")
//	pageIndex := c.MustGet("pageIndex").(uint)
//	pageSize := c.MustGet("pageSize").(uint)
//	chainName := c.MustGet("chainName").(string)
//	chainId := c.MustGet("chainId").(uint)
//	tokenAddress := c.Query("tokenAddress")
//
//	if address == "" {
//		response = global.Response{
//			Code: http.StatusInternalServerError,
//			Data: nil,
//			Msg:  "address is empty",
//		}
//		c.JSON(http.StatusInternalServerError, response)
//		return
//	}
//	// 查询链信息
//	configData, err := models.GetConfigData(chainName, chainId, "")
//	if err != nil {
//		response = global.Response{
//			Code: http.StatusInternalServerError,
//			Data: nil,
//			Msg:  err.Error(),
//		}
//		c.JSON(http.StatusInternalServerError, response)
//		return
//	}
//
//	// 查询代币详情
//	token := &models.TokenInfo{}
//	tokenInfo := &models.TokenInfo{}
//
//	// 主币交易
//	if len(tokenAddress) < 10 {
//		// 查询交易记录
//		dataList, err := models.GetMainRecordByAddressV2(configData.ChainName, address, pageIndex, pageSize)
//		if err != nil {
//			c.JSON(http.StatusInternalServerError, global.Response{
//				Code: http.StatusInternalServerError,
//				Data: nil,
//				Msg:  err.Error(),
//			})
//			return
//		}
//
//		c.JSON(http.StatusOK, global.Response{
//			Code: http.StatusOK,
//			Data: dataList,
//			Msg:  "",
//		})
//		return
//	} else {
//		tokenInfo = token.GetTokenInfoByAddress(tokenAddress)
//	}
//	if tokenInfo.Address == "" {
//		// 数据库中没有查询到 调用合约查询
//		client, err := ethclient.Dial(configData.RpcUrl)
//		if err != nil {
//			log.Println(err)
//		}
//		tokenName, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "name")
//		if err != nil {
//			c.JSON(http.StatusInternalServerError, global.Response{
//				Code: http.StatusInternalServerError,
//				Data: nil,
//				Msg:  err.Error(),
//			})
//			return
//		}
//		tokenSym, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "symbol")
//		if err != nil {
//			c.JSON(http.StatusInternalServerError, global.Response{
//				Code: http.StatusInternalServerError,
//				Data: nil,
//				Msg:  err.Error(),
//			})
//		}
//		tokenDec, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "decimals")
//		if err != nil {
//			c.JSON(http.StatusInternalServerError, global.Response{
//				Code: http.StatusInternalServerError,
//				Data: nil,
//				Msg:  err.Error(),
//			})
//			return
//		}
//		tokenTot, err := contract.CallContractMethod(client, common.HexToAddress(tokenAddress), evmAbi.ERC20_ABI, "totalSupply")
//		if err != nil {
//			c.JSON(http.StatusInternalServerError, global.Response{
//				Code: http.StatusInternalServerError,
//				Data: nil,
//				Msg:  err.Error(),
//			})
//			return
//		}
//
//		// 插入到token表中
//		tokenInfo.Name = tokenName[0].(string)
//		tokenInfo.Symbol = tokenSym[0].(string)
//		tokenInfo.Decimals = uint(tokenDec[0].(uint8))
//		tokenInfo.Address = common.HexToAddress(tokenAddress).Hex()
//		tokenInfo.ChainName = configData.ChainName
//		tokenInfo.ChainID = configData.ChainID
//		tokenInfo.TotalSupply = tokenTot[0].(*big.Int).String()
//		err = tokenInfo.AddToken()
//		if err != nil {
//			c.JSON(http.StatusInternalServerError, global.Response{
//				Code: http.StatusInternalServerError,
//				Data: nil,
//				Msg:  err.Error(),
//			})
//			return
//		}
//	}
//
//	// 查询交易记录
//	dataList, err := models.GetTokenRecordByAddressV2(configData.ChainName, address, tokenAddress, pageIndex, pageSize)
//	if err != nil {
//		c.JSON(http.StatusInternalServerError, global.Response{
//			Code: http.StatusInternalServerError,
//			Data: nil,
//			Msg:  err.Error(),
//		})
//		return
//	}
//
//	c.JSON(http.StatusOK, global.Response{
//		Code: http.StatusOK,
//		Data: dataList,
//		Msg:  "",
//	})
//
//}

func (v1 Block) GetTransferRecord(c *gin.Context) {
	//var response global.Response
	address := c.DefaultQuery("address", "")
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	flag := c.Query("flag") //0.全部 1.转出 2.转入
	tokenAddress := c.Query("tokenAddress")

	configData, err1 := models.GetConfigData(strings.ToUpper(chainName), chainId, "")
	if err1 != nil {
		c.JSON(http.StatusOK, global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err1.Error(),
		})
		return
	}

	tokenInfo := models.GetMainToken(strconv.FormatInt(configData.UdunId, 10))
	if tokenInfo == nil {
		c.JSON(http.StatusOK, global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取主币信息失败！",
		})
		return
	}

	pageIndexStr := "0"
	if strings.ToUpper(chainName) == "TRX" {
		pageIndexStr = strconv.Itoa(int(pageIndex) + 1)
	} else {
		pageIndexStr = strconv.Itoa(int(pageIndex) + 1)
	}

	pageSizeStr := strconv.Itoa(int(pageSize))

	var dataList []models.TransactionData
	var err error
	if strings.ToUpper(chainName) == "BSC" {
		if len(tokenAddress) < 10 {
			url := "https://api.bscscan.com/api?module=account&action=txlist&address=" + address + "&startblock=0&endblock=99999999&page=" + pageIndexStr + "&offset=" + pageSizeStr + "&sort=desc&apikey=HUKUIURCJ84867GFV2TQ4AY87UPP3V6VNZ"
			dataList, err = models.GetTransferData(url, flag, address, tokenInfo.Decimals)
		} else {
			url := "https://api.bscscan.com/api?module=account&action=tokentx&contractaddress=" + tokenAddress + "&address=" + address + "&page=" + pageIndexStr + "&offset=" + pageSizeStr + "&startblock=0&endblock=999999999&sort=desc&apikey=HUKUIURCJ84867GFV2TQ4AY87UPP3V6VNZ"
			dataList, err = models.GetTransferData(url, flag, address, tokenInfo.Decimals)
		}
	}
	if strings.ToUpper(chainName) == "ETH" {
		if len(tokenAddress) < 10 {
			url := "https://api.etherscan.io/api?module=account&action=txlist&address=" + address + "&startblock=0&endblock=99999999&page=" + pageIndexStr + "&offset=" + pageSizeStr + "&sort=desc&apikey=9VYNVCUMVSP1FEJQYYYTWWM6JHMPNDVXZC"
			var tempDataList []models.TransactionData
			tempDataList, err = models.GetTransferData(url, flag, address, tokenInfo.Decimals)
			for _, data := range tempDataList {
				if data.Amount != "0" {
					dataList = append(dataList, data)
				}
			}
		} else {
			url := "https://api.etherscan.io/api?module=account&action=tokentx&contractaddress=" + tokenAddress + "&address=" + address + "&page=" + pageIndexStr + "&offset=" + pageSizeStr + "&startblock=0&endblock=999999999&sort=desc&apikey=9VYNVCUMVSP1FEJQYYYTWWM6JHMPNDVXZC"
			dataList, err = models.GetTransferData(url, flag, address, tokenInfo.Decimals)
		}
	}

	if strings.ToUpper(chainName) == "POLYGON" {
		if len(tokenAddress) < 10 {
			url := "https://api.polygonscan.com/api?module=account&action=txlist&address=" + address + "&startblock=0&endblock=99999999&page=" + pageIndexStr + "&offset=" + pageSizeStr + "&sort=desc&apikey=7GGRS4YW5QZDF9RU63NU8E32GPQ6JUEFDE"
			var tempDataList []models.TransactionData
			tempDataList, err = models.GetTransferData(url, flag, address, tokenInfo.Decimals)
			for _, data := range tempDataList {
				if data.Amount != "0" {
					dataList = append(dataList, data)
				}
			}
		} else {
			url := "https://api.polygonscan.com/api?module=account&action=tokentx&contractaddress=" + tokenAddress + "&address=" + address + "&page=" + pageIndexStr + "&offset=" + pageSizeStr + "&startblock=0&endblock=999999999&sort=desc&apikey=7GGRS4YW5QZDF9RU63NU8E32GPQ6JUEFDE"
			dataList, err = models.GetTransferData(url, flag, address, tokenInfo.Decimals)
		}
	}

	if strings.ToUpper(chainName) == "TRX" {
		if len(tokenAddress) < 10 {
			url := "https://apilist.tronscanapi.com/api/transfer/trx?address=" + address + "&start=" + pageIndexStr + "&limit=" + pageSizeStr + "&direction=" + flag + "&reverse=true&fee=false&db_version=1&start_timestamp=&end_timestamp="
			dataList, err = models.GetTrxTransferData(url)
		} else {
			url := "https://apilist.tronscanapi.com/api/transfer/trc20?address=" + address + "&trc20Id=" + tokenAddress + "&start=" + pageIndexStr + "&limit=" + pageSizeStr + "&direction=" + flag + "&reverse=true&db_version=1&start_timestamp=&end_timestamp="
			dataList, err = models.GetTrxTransferData(url)
		}
	}

	if err != nil {
		c.JSON(http.StatusOK, global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, global.Response{
		Code: http.StatusOK,
		Data: dataList,
		Msg:  "",
	})

}

type Response struct {
	Result []struct {
		DisplayData struct {
			ResultData struct {
				TplData struct {
					Result struct {
						MinuteData struct {
							Cur struct {
								Price string `json:"price"`
							} `json:"cur"`
						} `json:"minute_data"`
					} `json:"result"`
				} `json:"tplData"`
			} `json:"resultData"`
		} `json:"DisplayData"`
	} `json:"Result"`
}

func (v1 Block) GetPrice(c *gin.Context) {

	var response global.Response
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)
	address := c.Query("address")
	tokenAddress := c.Query("tokenAddress")
	currencyType := c.Query("currencyType") //货币类型  韩元KRW 日元JPY 人民币CNY 美元USD
	if address == "" || currencyType == "" {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "address is empty",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	// 创建结构体
	type BalanceInfo struct {
		Token string `json:"token"`
		Price string `json:"price"`
		Rate  string `json:"rate"`
	}

	rate := "1"

	//if currencyType != "USD" {
	//	url := "https://gushitong.baidu.com/opendata?openapi=1&dspName=iphone&tn=tangram&client=app&query=USD" + currencyType + "&code=&word=&resource_id=5343&ma_ver=4&finClientType=pc"
	//	body, err := tools.SendGet(url)
	//	if err != nil {
	//		response = global.Response{
	//			Code: http.StatusInternalServerError,
	//			Data: nil,
	//			Msg:  err.Error(),
	//		}
	//		c.JSON(http.StatusInternalServerError, response)
	//		return
	//	}
	//	var data Response
	//	_ = json.Unmarshal(body, &data)
	//	rate = data.Result[0].DisplayData.ResultData.TplData.Result.MinuteData.Cur.Price
	//}

	if currencyType != "USD" {
		redisValue, err := global.RedisEngine.Get(context.TODO(), currencyType).Result()
		if err != nil {
			response = global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			}
			c.JSON(http.StatusInternalServerError, response)
			return
		}
		rate = redisValue
	}

	configData, err := models.GetConfigData(strings.ToUpper(chainName), chainId, "")
	if err != nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	usdtInfo := models.GetMainToken(configData.UsdtAddress)
	if usdtInfo == nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取usdt信息失败!",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	var balanceList []BalanceInfo

	// 通过rpc地址获取公链币余额
	//client, err := ethclient.Dial(configData.RpcUrl)
	//if err != nil {
	//	response = global.Response{
	//		Code: http.StatusInternalServerError,
	//		Data: nil,
	//		Msg:  err.Error(),
	//	}
	//	c.JSON(http.StatusInternalServerError, response)
	//	return
	//}
	//defer client.Close()

	client := global.ConnPool.Get(configData.RpcUrl)
	if client == nil {
		// 如果没有可用连接，创建一个新的连接
		client, err = ethclient.Dial(configData.RpcUrl)
		if err != nil {
			response := global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			}
			c.JSON(http.StatusInternalServerError, response)
			return
		}
	}
	defer global.ConnPool.Put(configData.RpcUrl, client)

	tokenInfo := models.GetMainToken(strconv.FormatInt(configData.UdunId, 10))
	if tokenInfo == nil {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取主币信息失败!",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	mainPrice := getCurrentPrice(client, configData.MainAddress, configData, tokenInfo.Decimals, usdtInfo.Decimals)
	balanceList = append(balanceList, BalanceInfo{
		Token: strconv.FormatInt(configData.ChainID, 10),
		Price: mainPrice,
		Rate:  rate,
	})

	if tokenAddress != "" {

		var wg sync.WaitGroup
		var mu sync.Mutex // 用于保护对 balanceList 的并发写入
		tokenArr := strings.Split(tokenAddress, ",")

		for _, token := range tokenArr {
			wg.Add(1) // 增加 WaitGroup 计数
			go func(token string) {
				defer wg.Done() // 在 goroutine 完成时调用 Done

				contractAddress := common.HexToAddress(token)
				decimals, err := contract.CallContractMethod(client, contractAddress, evmAbi.ERC20_ABI, "decimals")
				if err != nil {
					// 处理错误（可以选择记录日志或返回特定值）
					log.Println("获取精度错误:", err)
					return
				}

				price := getCurrentPrice(client, token, configData, uint(decimals[0].(uint8)), usdtInfo.Decimals)

				mu.Lock() // 在写入 balanceList 前加锁
				balanceList = append(balanceList, BalanceInfo{
					Token: token,
					Price: price,
					Rate:  rate,
				})
				mu.Unlock() // 解锁
			}(token) // 将 token 作为参数传递给 goroutine
		}

		wg.Wait()
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: balanceList,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}

func getCurrentPrice(client *ethclient.Client, tokenAddress string, configData models.ScanConfig, decimal uint, usdtDecimal uint) string {
	if common.HexToAddress(tokenAddress).Hex() == common.HexToAddress(configData.UsdtAddress).Hex() {
		return "1"
	}
	routerABI, err := abi.JSON(strings.NewReader(evmAbi.UNISWAP_V2_ROUTER))
	if err != nil {
		log.Println("UNISWAP_V2_ROUTER解析失败", err)
		return "0"
	}

	// 使用 big.Int 来设置代币数量，避免浮点数精度问题
	amountIn := new(big.Int).Mul(big.NewInt(1), new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimal)), nil))

	path := []common.Address{
		common.HexToAddress(tokenAddress),
		common.HexToAddress(configData.UsdtAddress),
	}

	// 创建调用参数
	callData, err := routerABI.Pack("getAmountsOut", amountIn, path)
	if err != nil {
		log.Println("routerABI.Pack error:", err)
		return "0"
	}

	routerAddress := common.HexToAddress(configData.RouterAddress)
	msg := ethereum.CallMsg{
		To:   &routerAddress,
		Data: callData,
	}

	// 调用合约方法
	result, err := client.CallContract(context.Background(), msg, nil)
	if err != nil {
		log.Println("CallContract error:", err)
		return "0"
	}

	// 解析返回结果
	var amounts []*big.Int
	err = routerABI.UnpackIntoInterface(&amounts, "getAmountsOut", result)
	if err != nil {
		log.Println("UnpackIntoInterface error:", err)
		return "0"
	}

	// 获取当前价格
	if len(amounts) > 1 {
		//根据换出来的数字 再除以usdt的精度 得到价格

		bigInt := new(big.Int).Mul(big.NewInt(1), new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(usdtDecimal)), nil))

		price := new(big.Float).Quo(new(big.Float).SetInt(amounts[1]), new(big.Float).SetInt(bigInt))
		priceStr := price.Text('f', int(decimal))
		return priceStr
	} else {
		return "0"
	}
}

func (v1 Block) SwapList(c *gin.Context) {

	type Result struct {
		TokenASymbol string `json:"tokenASymbol"`
		TokenBSymbol string `json:"tokenBSymbol"`
		Price        string `json:"price"`      //币价
		Percentage   string `json:"percentage"` //百分比
		Type         string `json:"type"`
	}

	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)

	var listenModel models.ListenSwapAddressConfig
	listenModel.ChainName = chainName
	listenModel.ChainId = chainId

	list, err := listenModel.List()
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取底池列表失败!",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	var resultArr []Result

	for _, listen := range list {
		var swapInfo models.SwapTransactionInfo
		var result Result
		result.TokenASymbol = listen.TokenASymbol
		result.TokenBSymbol = listen.TokenBSymbol
		swapClient := global.DBEngine.Database(global.DbConfig.DbName).Collection(listen.TokenASymbol + "_" + listen.TokenBSymbol + "_" + "transaction_info")
		err = swapClient.FindOne(context.Background(), bson.M{"_id": -1}).Decode(&swapInfo)
		result.Price = swapInfo.Price
		if err != nil {
			configData, err := models.GetConfigData(strings.ToUpper(chainName), chainId, "DAPP")
			if err != nil {
				response := global.Response{
					Code: http.StatusInternalServerError,
					Data: nil,
					Msg:  err.Error(),
				}
				c.JSON(http.StatusInternalServerError, response)
				return
			}

			// 通过rpc地址获取公链币余额
			client, err := ethclient.Dial(configData.RpcUrl)
			if err != nil {
				response := global.Response{
					Code: http.StatusInternalServerError,
					Data: nil,
					Msg:  err.Error(),
				}
				c.JSON(http.StatusInternalServerError, response)
				return
			}
			defer client.Close()
			result.Price = getCurrentPrice(client, listen.TokenB, configData, listen.TokenBDecimal, listen.TokenADecimal)
			result.Percentage = "0"
			result.Type = "+"
		} else {

			var oldSwapInfo models.SwapTransactionInfo
			twentyFourHoursBefore := time.Unix(swapInfo.Timestamp, 0).Add(-24 * time.Hour)
			// 查询条件
			filter := bson.M{
				"timestamp_field": bson.M{
					"$lt": twentyFourHoursBefore,
				},
			}
			err = swapClient.FindOne(context.Background(), filter).Decode(&oldSwapInfo)
			if err != nil {
				result.Percentage = "0"
			}
			result.Percentage = tools.Mul(swapInfo.Price, oldSwapInfo.Price)

			num1, _ := strconv.ParseFloat(swapInfo.Price, 64)
			num2, _ := strconv.ParseFloat(oldSwapInfo.Price, 64)
			if num1-num2 > 0 {
				result.Type = "+"
			} else {
				result.Type = "-"
			}

		}

		resultArr = append(resultArr, result)
	}

	response := global.Response{
		Code: http.StatusOK,
		Data: resultArr,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}

func (v1 Block) KlineData(c *gin.Context) {
	tokenASymbol := c.Query("tokenASymbol")
	tokenBSymbol := c.Query("tokenBSymbol")
	typeVal := c.Query("type")
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)

	var result []models.Kline

	klineClient := global.DBEngine.Database(global.DbConfig.DbName).Collection(tokenASymbol + "_" + tokenBSymbol + "_kline_" + typeVal)
	find, err := klineClient.Find(context.Background(), bson.M{"timestamp": bson.M{"$gte": time.Now().Unix() - 30*24*60*60}}, options.Find().SetSort(bson.D{{"timestamp", 1}}))
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}
	err = find.All(context.Background(), &result)
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	swapClient := global.DBEngine.Database(global.DbConfig.DbName).Collection(tokenASymbol + "_" + tokenBSymbol + "_" + "transaction_info")
	swapFind, err := swapClient.Find(context.Background(), bson.M{"timestamp": bson.M{"$gte": time.Now().Unix() - 24*60*60}}, options.Find().SetSort(bson.D{{"timestamp", -1}}))
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	var swapInfo []models.SwapTransactionInfo
	err = swapFind.All(context.Background(), &swapInfo)
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	// 定义4个变量:24小时内最高价 24小时内最低价 24小时内成交量 24小时内成交额 24小时交易地址数 24小时涨幅榜
	var high float64 = 0
	var low float64 = 0
	var volume float64 = 0
	var turnover float64 = 0
	addressMap := map[string]bool{}
	var change float64 = 0
	var poolAddress string

	// 选择数据库和集合
	kline1mClient := global.DBEngine.Database(global.DbConfig.DbName).Collection(tokenASymbol + "_" + tokenBSymbol + "_kline_1m")

	// 获取 24 小时之前的时间戳
	thresholdTime := time.Now().Add(-24*time.Hour).Unix() * 1000

	// MongoDB 聚合管道
	pipeline := mongo.Pipeline{
		{
			{"$match", bson.D{
				{"timestamp", bson.D{{"$gt", thresholdTime}}},
			}},
		},
		{
			{"$group", bson.D{
				{"_id", nil},
				{"maxHigh", bson.D{{"$max", "$high"}}},
				{"minLow", bson.D{{"$min", "$low"}}},
			}},
		},
	}

	// 执行聚合查询
	cursor, err := kline1mClient.Aggregate(context.TODO(), pipeline)
	if err != nil {
		log.Fatal(err)
	}
	defer cursor.Close(context.TODO())

	// 解析结果

	if cursor.Next(context.Background()) {
		var data bson.M
		if err := cursor.Decode(&data); err != nil {
			log.Fatal(err)
		}
		//fmt.Printf("High 最大值: %v\n", data["maxHigh"])
		//fmt.Printf("Low 最小值: %v\n", data["minLow"])
		high = data["maxHigh"].(float64)
		low = data["minLow"].(float64)
	}

	var listenModel models.ListenSwapAddressConfig

	collection := global.DBEngine.Database(global.DbConfig.DbName).Collection("listen_swap_address_config")

	filter := bson.M{
		"$and": []bson.M{
			{
				"$or": []bson.M{
					{
						"tokenASymbol": tokenASymbol,
						"tokenBSymbol": tokenBSymbol,
					},
					{
						"tokenASymbol": tokenBSymbol,
						"tokenBSymbol": tokenASymbol,
					},
				},
			},
			{
				"chainName": chainName,
				"chainId":   chainId,
			},
		},
	}

	err = collection.FindOne(context.Background(), filter).Decode(&listenModel)
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "查询底池错误" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return

	}

	for i, item := range swapInfo {
		//priceF, _ := strconv.ParseFloat(item.Price, 64)
		//valueF, _ := strconv.ParseFloat(item.Value, 64)
		//
		//if priceF == 0 {
		//	volume = 0
		//} else {
		//	// 计算总成交量
		//	volume = volume + (valueF / priceF)
		//}
		//
		//// 计算总成交额
		//turnover = turnover + valueF

		if item.Type == 1 {
			var usdtAmount float64
			var tokenAmount float64
			if listenModel.TokenASymbol == "USDT" {
				usdtAmount, _ = strconv.ParseFloat(item.Amount0In, 64)
				tokenAmount, _ = strconv.ParseFloat(item.Amount1Out, 64)
			} else {
				usdtAmount, _ = strconv.ParseFloat(item.Amount1In, 64)
				tokenAmount, _ = strconv.ParseFloat(item.Amount0Out, 64)
			}
			volume += tokenAmount
			turnover += usdtAmount
		} else {
			var usdtAmount float64
			var tokenAmount float64
			if listenModel.TokenASymbol == "USDT" {
				usdtAmount, _ = strconv.ParseFloat(item.Amount0Out, 64)
				tokenAmount, _ = strconv.ParseFloat(item.Amount1In, 64)
			} else {
				usdtAmount, _ = strconv.ParseFloat(item.Amount1Out, 64)
				tokenAmount, _ = strconv.ParseFloat(item.Amount0In, 64)
			}
			volume += tokenAmount
			turnover += usdtAmount
		}
		addressMap[item.From] = true

		if poolAddress == "" {
			poolAddress = item.SwapAddress
		}

		//计算涨跌幅
		if i == 0 {
			var swapKline models.Kline
			klineClient1d := global.DBEngine.Database(global.DbConfig.DbName).Collection(tokenASymbol + "_" + tokenBSymbol + "_kline_1d")
			err = klineClient1d.FindOne(
				context.Background(),
				bson.M{}, // 查询条件
				options.FindOne().SetSort(bson.D{{"timestamp", -1}}).SetSkip(1), // 排序、跳过第一条
			).Decode(&swapKline)
			if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
				response := global.Response{
					Code: http.StatusInternalServerError,
					Data: nil,
					Msg:  err.Error(),
				}
				c.JSON(http.StatusInternalServerError, response)
				return
			}
			thatPrice, _ := strconv.ParseFloat(item.Price, 64)

			// 计算涨跌幅
			var changePercentage float64
			if swapKline.Close == 0 {
				changePercentage = thatPrice * 100
			} else {
				changePercentage = (thatPrice - swapKline.Close) / swapKline.Close * 100
			}

			// 保留两位小数
			change = math.Round(changePercentage*100) / 100
		}
	}

	configData, _ := models.GetConfigData(strings.ToUpper(chainName), chainId, "DAPP")

	client, err := ethclient.Dial(configData.RpcUrl)
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "链接链信息" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	var tokenAddress string
	var tokenDecimal uint
	var usdtDecimal uint

	if listenModel.TokenASymbol == "USDT" {
		tokenAddress = listenModel.TokenB
		tokenDecimal = listenModel.TokenBDecimal
		usdtDecimal = listenModel.TokenADecimal
	} else {
		tokenAddress = listenModel.TokenA
		tokenDecimal = listenModel.TokenADecimal
		usdtDecimal = listenModel.TokenBDecimal
	}

	price := getCurrentPrice(client, tokenAddress, configData, tokenDecimal, usdtDecimal)

	response := global.Response{
		Code: http.StatusOK,
		Data: map[string]interface{}{
			"high":         high,
			"low":          low,
			"volume":       volume,   //成交量  代币数量
			"turnover":     turnover, //成交额  usdt数量
			"kline":        result,
			"addressCount": len(addressMap),
			"price":        price,
			"change":       change,
		},
		Msg: "success",
	}

	c.JSON(http.StatusOK, response)

}

func (v1 Block) PoolList(c *gin.Context) {
	chainName := c.MustGet("chainName").(string)
	chainId := c.MustGet("chainId").(uint)

	var listenModel models.ListenSwapAddressConfig
	listenModel.ChainName = chainName
	listenModel.ChainId = chainId

	list, err := listenModel.List()
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取底池列表失败!",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	type Result struct {
		Token   string  `json:"token"`
		Symbol  string  `json:"symbol"`
		Price   float64 `json:"price"`
		Change  string  `json:"change"`
		Address string  `json:"address"`
	}

	var result []Result
	var swapKline models.Kline

	for _, config := range list {
		var swapInfo models.SwapTransactionInfo
		var tableName string
		var tokenAddress string
		if config.TokenASymbol == "USDT" {
			tableName = config.TokenBSymbol
			tokenAddress = config.TokenB
		} else {
			tableName = config.TokenASymbol
			tokenAddress = config.TokenA
		}
		address := config.Address
		// 查询当前价格
		thatKlineClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("USDT_" + tableName + "_" + "transaction_info")
		err := thatKlineClient.FindOne(context.Background(), bson.M{}, options.FindOne().SetSort(bson.D{{"timestamp", -1}})).Decode(&swapInfo)
		if err != nil {
			// 没有价格返回0
			result = append(result, Result{
				Token:   tokenAddress,
				Symbol:  tableName,
				Price:   0,
				Change:  "0",
				Address: address,
			})
		}

		thatPrice, _ := strconv.ParseFloat(swapInfo.CurrentPrice, 64)
		thatPrice, _ = strconv.ParseFloat(fmt.Sprintf("%.6f", thatPrice), 64)
		klineClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("USDT_" + tableName + "_kline_1d")
		//err = klineClient.FindOne(context.Background(), bson.M{}, options.FindOne().SetSort(bson.D{{"timestamp", -1}})).Decode(&swapKline)

		err = klineClient.FindOne(
			context.Background(),
			bson.M{}, // 查询条件
			options.FindOne().SetSort(bson.D{{"timestamp", -1}}).SetSkip(1), // 排序、跳过第一条
		).Decode(&swapKline)
		if err != nil {
			// 没有24小时前数据 涨跌幅为0
			result = append(result, Result{
				Token:   tokenAddress,
				Symbol:  tableName,
				Price:   thatPrice,
				Change:  "0",
				Address: address,
			})
		} else {
			// 计算涨跌幅
			changePercentage := (thatPrice - swapKline.Close) / swapKline.Close * 100
			// 保留四位小数并补零
			formattedChangePercentage := fmt.Sprintf("%.4f", changePercentage)
			result = append(result, Result{
				Token:   tokenAddress,
				Symbol:  tableName,
				Price:   thatPrice,
				Change:  formattedChangePercentage,
				Address: address,
			})
		}
	}

	response := global.Response{
		Code: http.StatusOK,
		Data: result,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)
}

func (v1 Block) PoolTradeList(c *gin.Context) {

	tokenSymbol := c.Query("tokenSymbol")
	typeVal := c.Query("type")
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	address := c.Query("address")

	if tokenSymbol == "" {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "tokenSymbol is required",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	filter := bson.M{}
	if typeVal != "0" {
		//typeVal转int类型
		filter["type"], _ = strconv.Atoi(typeVal)
	}

	if address != "" {

		if typeVal == "1" {
			filter["from"] = common.HexToAddress(address).Hex()
		}
		if typeVal == "2" {
			filter["to"] = common.HexToAddress(address).Hex()
		}
		//filter加from或者to等于address
		filter["$or"] = []bson.M{
			{"from": common.HexToAddress(address).Hex()},
			{"to": common.HexToAddress(address).Hex()},
		}
	}

	optionFind := options.Find().SetSort(bson.D{{"timestamp", -1}}).SetLimit(int64(pageSize)).SetSkip(int64(pageIndex))

	client := global.DBEngine.Database(global.DbConfig.DbName).Collection("USDT_" + tokenSymbol + "_" + "transaction_info")
	find, err := client.Find(context.Background(), filter, optionFind, options.Find().SetSort(bson.D{{"timestamp", -1}}))

	if err != nil && err.Error() != "mongo: no documents in result" {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	type Result struct {
		Address     string `json:"address"` //地址 如果是转入就是from地址 如果是转出就是to地址
		Amount      string `json:"amount"`  //数量
		TimeStamp   int64  `json:"timeStamp"`
		Type        int    `json:"type"`        //1.买 2.卖
		Price       string `json:"price"`       //币价
		Value       string `json:"value"`       //价值
		UsdtAmount  string `json:"usdtAmount"`  //进或者出usdt的数量
		TokenAmount string `json:"tokenAmount"` //进或者出代币的数量
	}
	var resultList []Result
	var listenModel models.ListenSwapAddressConfig
	listenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("listen_swap_address_config")
	for find.Next(context.Background()) {
		var item models.SwapTransactionInfo
		if err = find.Decode(&item); err != nil {
			log.Println("解析出错:", err)
			continue
		}

		if listenModel.Address == "" {
			err = listenClient.FindOne(context.Background(), bson.M{"address": item.SwapAddress}).Decode(&listenModel)
			if err != nil {
				log.Println("查询底池信息出错:", err)
				continue
			}
		}

		var result Result

		result.TimeStamp = item.Timestamp
		result.Type = item.Type
		result.Price = item.CurrentPrice
		//result.Value = item.Value
		if item.Type == 1 {
			result.Address = item.From

			if listenModel.TokenASymbol == "USDT" {
				result.UsdtAmount = item.Amount0In
				result.TokenAmount = item.Amount1Out
				result.Amount = item.Amount1Out
				result.Value = item.Amount0In
			} else {
				result.UsdtAmount = item.Amount1In
				result.TokenAmount = item.Amount0Out
				result.Amount = item.Amount0Out
				result.Value = item.Amount1In
			}

		} else {
			result.Address = item.To
			result.Amount = item.Amount1Out

			if listenModel.TokenASymbol == "USDT" {
				result.UsdtAmount = item.Amount0Out
				result.TokenAmount = item.Amount1In
				result.Amount = item.Amount1In
				result.Value = item.Amount0Out
			} else {
				result.UsdtAmount = item.Amount1Out
				result.TokenAmount = item.Amount0In
				result.Amount = item.Amount0In
				result.Value = item.Amount1Out
			}
		}
		//result.Value = item.Value
		resultList = append(resultList, result)
	}

	response := global.Response{
		Code: http.StatusOK,
		Data: resultList,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}

func (v1 Block) PoolInfo(c *gin.Context) {

	poolAddress := c.Query("poolAddress")

	if poolAddress == "" {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "poolAddress is required",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	//通过地址查询池信息
	listenModel := models.ListenSwapAddressConfig{}
	listenModel.Address = poolAddress
	poolInfo, err := listenModel.GetInfo()
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取池信息失败!" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	config, err := models.GetConfigData(poolInfo.ChainName, poolInfo.ChainId, "DAPP")
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取链信息失败!" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	client, err := ethclient.Dial(config.RpcUrl)
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "链接rpcUrl失败!" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	var usdtAddress string
	var tokenAddress string

	var usdtDecimal uint
	var tokenDecimal uint

	if poolInfo.TokenA == config.UsdtAddress {
		usdtAddress = poolInfo.TokenA
		tokenAddress = poolInfo.TokenB

		usdtDecimal = poolInfo.TokenADecimal
		tokenDecimal = poolInfo.TokenBDecimal
	} else {
		usdtAddress = poolInfo.TokenB
		tokenAddress = poolInfo.TokenA

		tokenDecimal = poolInfo.TokenBDecimal
		usdtDecimal = poolInfo.TokenADecimal
	}

	// 获取第一个代币的余额
	tokenBalance, err := utils.GetTokenBalance(client, c, tokenAddress, poolInfo.Address, int32(tokenDecimal))
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取token1数量失败!" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	// 获取第二个代币的余额
	usdtBalance, err := utils.GetTokenBalance(client, c, usdtAddress, poolInfo.Address, int32(usdtDecimal))
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取token2数量失败!" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	type Result struct {
		Size   string `json:"size"`
		Value  string `json:"value"`
		Name   string `json:"name"`
		Amount string `json:"amount"`
	}
	var result Result
	result.Size = tools.Muliplication(usdtBalance, "2")
	result.Value = tools.Div(usdtBalance, tokenBalance, 18)
	result.Name = poolInfo.TokenASymbol + "/" + poolInfo.TokenBSymbol
	result.Amount = tokenBalance + "/" + usdtBalance

	response := global.Response{
		Code: http.StatusOK,
		Data: result,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}

type MarketInfo struct {
	PriceInUsd float64 `json:"priceInUsd"`
}

type Trc20Token struct {
	MarketInfo MarketInfo `json:"market_info"`
}

type TrxResponse struct {
	Trc20Tokens []Trc20Token `json:"trc20_tokens"`
}

func (v1 Block) GetTrxPrice(c *gin.Context) {
	var response global.Response
	//chainName := c.MustGet("chainName").(string)
	//chainId := c.MustGet("chainId").(uint)
	//address := c.Query("address")
	tokenAddress := c.Query("tokenAddress")
	currencyType := c.Query("currencyType") //货币类型  韩元KRW 日元JPY 人民币CNY 美元USD
	if currencyType == "" {
		response = global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "currencyType is empty",
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	// 创建结构体
	type BalanceInfo struct {
		Token string `json:"token"`
		Price string `json:"price"`
		Rate  string `json:"rate"`
	}

	rate := "1"

	if currencyType != "USD" {
		url := "https://gushitong.baidu.com/opendata?openapi=1&dspName=iphone&tn=tangram&client=app&query=USD" + currencyType + "&code=&word=&resource_id=5343&ma_ver=4&finClientType=pc"
		body, err := tools.SendGet(url)
		if err != nil {
			response = global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			}
			c.JSON(http.StatusInternalServerError, response)
			return
		}
		var data Response
		_ = json.Unmarshal(body, &data)
		rate = data.Result[0].DisplayData.ResultData.TplData.Result.MinuteData.Cur.Price
	}

	var balanceList []BalanceInfo

	balanceList = append(balanceList, BalanceInfo{
		Token: "648126",
		Price: "0",
		Rate:  rate,
	})
	if tokenAddress != "" {
		tokenArr := strings.Split(tokenAddress, ",")

		for _, token := range tokenArr {
			url := "https://apilist.tronscanapi.com/api/token_trc20?contract=" + token + "&showAll=1&start=&limit="
			time.Sleep(500 * time.Millisecond)
			body, err := tools.SendGet(url)
			fmt.Println("err:", err)
			if err != nil {
				response = global.Response{
					Code: http.StatusInternalServerError,
					Data: nil,
					Msg:  err.Error(),
				}
				c.JSON(http.StatusInternalServerError, response)
				return
			}
			var data TrxResponse
			_ = json.Unmarshal(body, &data)

			var price float64
			if len(data.Trc20Tokens) == 0 {
				price = 0
			} else {
				price = data.Trc20Tokens[0].MarketInfo.PriceInUsd
			}

			balanceList = append(balanceList, BalanceInfo{
				Token: token,
				Price: fmt.Sprintf("%f", price),
				Rate:  rate,
			})
		}
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: balanceList,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}

func (v1 Block) GetToken(c *gin.Context) {
	poolAddress := c.Query("poolAddress")
	if poolAddress == "" {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "poolAddress is required",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	//通过地址查询池信息
	listenModel := models.ListenSwapAddressConfig{}
	listenModel.Address = poolAddress
	poolInfo, err := listenModel.GetInfo()
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取池信息失败!" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	var tokenSymbol string
	var tokenAddress string
	if poolInfo.TokenASymbol == "USDT" {
		tokenSymbol = poolInfo.TokenBSymbol
		tokenAddress = poolInfo.TokenB
	} else {
		tokenSymbol = poolInfo.TokenASymbol
		tokenAddress = poolInfo.TokenA
	}

	token := &models.TokenInfo{}
	tokenInfo := token.GetTokenInfoByAddress(tokenAddress)

	if tokenInfo == nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  "获取代币信息失败!" + err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	//tokenInfo.TotalSupply 除以10的18次幂

	tenTo18 := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(tokenInfo.Decimals)), nil)

	totalSupply := tools.Div(tokenInfo.TotalSupply, tenTo18.String(), -1)

	result := map[string]string{
		"total_supply": totalSupply,
		"address":      tokenAddress,
		"symbol":       tokenSymbol,
	}

	response := global.Response{
		Code: http.StatusOK,
		Data: result,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)
}

func (v1 Block) Get24HourData(c *gin.Context) {
	tokenSymbol := c.Query("tokenSymbol")

	if tokenSymbol == "" {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "tokenSymbol is required",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	client := global.DBEngine.Database(global.DbConfig.DbName).Collection("USDT_" + tokenSymbol + "_" + "transaction_info")
	find, err := client.Find(context.Background(), bson.M{"timestamp": bson.M{"$gte": time.Now().Unix() - 24*60*60}}, options.Find().SetSort(bson.D{{"timestamp", -1}}))

	fmt.Println("time:", time.Now().Unix()-24*60*60)
	if err != nil && err.Error() != "mongo: no documents in result" {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusInternalServerError, response)
		return
	}

	type LineChartInt struct {
		Name string `json:"name"`
		Data []int  `json:"data"`
	}
	type LineChartFloat struct {
		Name string    `json:"name"`
		Data []float64 `json:"data"`
	}
	//某个时间戳下的买入卖出地址数量
	type AddressList struct {
		Timestamp int64   `json:"timestamp"`
		BuyCount  int     `json:"buyCount"`
		SellCount int     `json:"sellCount"`
		BuyValue  float64 `json:"buyValue"`
		SellValue float64 `json:"sellValue"`
	}

	type Result struct {
		BuyCount        int64                 `json:"buyCount"`        //24h买入地址数
		SellCount       int64                 `json:"sellCount"`       //24h卖出地址数
		AddValue        float64               `json:"addValue"`        //24h增加量
		DecrValue       float64               `json:"decrValue"`       //24h减少量
		BuyAddressList  LineChartInt          `json:"buyAddressList"`  //买入折线图address数据
		SellAddressList LineChartInt          `json:"sellAddressList"` //卖入折线图address数据
		BuyValueList    LineChartFloat        `json:"buyValueList"`    //折线图资金池数据
		SellValueList   LineChartFloat        `json:"sellValueList"`   //折线图资金池数据
		TimeList        []int64               `json:"timeList"`        //前24小时的时间戳
		AddressList     map[int64]AddressList `json:"addressList"`
	}

	var data Result
	buyAddressSet := make(map[string]struct{})
	sellAddressSet := make(map[string]struct{})

	var addressMap = make(map[int64]AddressList)
	////获取当前时间的前24小时 以每小时为一个节点 存入TimeList
	for i := 0; i < 24; i++ {
		var addressData AddressList
		addressData.Timestamp = time.Now().Add(-time.Duration(i) * time.Hour).Truncate(time.Hour).Unix()
		addressMap[addressData.Timestamp] = addressData
	}

	var buyCount int64
	var sellCount int64
	for find.Next(context.Background()) {
		var item models.SwapTransactionInfo
		if err = find.Decode(&item); err != nil {
			log.Println("解析出错:", err)
			continue
		}
		t := time.Unix(item.Timestamp, 0).Truncate(time.Hour)
		mapData := addressMap[t.Unix()]
		if item.Type == 1 {
			//string转float64
			add, _ := strconv.ParseFloat(item.Price, 64)
			data.AddValue += math.Round(add*10000) / 10000
			mapData.BuyCount++
			mapData.BuyValue += add
			buyAddressSet[item.From] = struct{}{}
			buyCount++
		} else {
			sellAddressSet[item.From] = struct{}{}
			decr, _ := strconv.ParseFloat(item.Price, 64)
			data.DecrValue += math.Round(decr*10000) / 10000
			mapData.SellCount++
			mapData.SellValue += decr
			sellCount++
		}

		addressMap[t.Unix()] = mapData

	}

	data.BuyCount = buyCount
	data.SellCount = sellCount
	//data.AddressList = addressMap

	var timeList []int64
	var buyAddressList []int
	var sellAddressList []int
	var buyValueList []float64
	var sellValueList []float64

	var keys []int64
	for k := range addressMap {
		keys = append(keys, k)
	}

	// 对键进行排序
	sort.Slice(keys, func(i, j int) bool {
		return keys[i] > keys[j]
	})

	for _, k := range keys {
		v := addressMap[k]
		timeList = append(timeList, v.Timestamp)
		buyAddressList = append(buyAddressList, v.BuyCount)
		sellAddressList = append(sellAddressList, v.SellCount)
		buyValueList = append(buyValueList, v.BuyValue)
		sellValueList = append(sellValueList, v.SellValue)
	}
	data.TimeList = timeList
	data.BuyAddressList.Name = "买入地址数"
	data.BuyAddressList.Data = buyAddressList
	data.SellAddressList.Name = "卖出地址数"
	data.SellAddressList.Data = sellAddressList
	data.BuyValueList.Name = "买入资金池"
	data.BuyValueList.Data = buyValueList
	data.SellValueList.Name = "卖出资金池"
	data.SellValueList.Data = sellValueList

	response := global.Response{
		Code: http.StatusOK,
		Data: data,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}

func (v1 Block) PoolRecordList(c *gin.Context) {
	address := c.Query("address")
	if address == "" {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "address is required",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	typeVal := c.Query("type")

	typeInt, err := strconv.ParseUint(typeVal, 10, 0)
	if err != nil {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "Parse type error",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	var listenModel models.ListenSwapAddressConfig
	listenModel.Address = address
	info, err := listenModel.GetInfo()
	if err != nil {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "info not found",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	var tokenSymbol string

	if info.TokenASymbol == "USDT" {
		tokenSymbol = info.TokenBSymbol
	} else {
		tokenSymbol = info.TokenASymbol
	}
	poolList, err := models.GetPoolList(tokenSymbol, pageIndex, pageSize, int(typeInt))

	if err != nil {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "poolList not found",
		}
		c.JSON(http.StatusBadRequest, response)
		return
	}

	type Response struct {
		Type      int    `json:"type"`
		TimeStamp uint64 `json:"timeStamp"`
		Amount0   string `json:"amount0"`
		Amount1   string `json:"amount1"`
		Address   string `json:"address"`
	}

	var results []Response
	for _, transaction := range poolList {
		var result Response

		result.Type = transaction.Type
		result.TimeStamp = transaction.Timestamp
		result.Amount0 = transaction.Amount0 + " " + info.TokenASymbol
		result.Amount1 = transaction.Amount1 + " " + info.TokenBSymbol
		result.Address = transaction.From
		results = append(results, result)
	}

	response := global.Response{
		Code: http.StatusOK,
		Data: results,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}

func (v1 Block) GetExchangeRate(c *gin.Context) {

	var response global.Response

	currencyType := c.Query("currencyType") //货币类型  韩元KRW 日元JPY 人民币CNY 美元USD

	rate := "1"

	if currencyType != "USD" {
		url := "https://gushitong.baidu.com/opendata?openapi=1&dspName=iphone&tn=tangram&client=app&query=USD" + currencyType + "&code=&word=&resource_id=5343&ma_ver=4&finClientType=pc"
		body, err := tools.SendGet(url)
		if err != nil {
			response = global.Response{
				Code: http.StatusInternalServerError,
				Data: nil,
				Msg:  err.Error(),
			}
			c.JSON(http.StatusInternalServerError, response)
			return
		}
		var data Response
		_ = json.Unmarshal(body, &data)
		rate = data.Result[0].DisplayData.ResultData.TplData.Result.MinuteData.Cur.Price
	}

	response = global.Response{
		Code: http.StatusOK,
		Data: rate,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)

}
